Virtually all applications—from desktop applications to enterprise applications—access data in some form or fashion. When the data to be accessed resides in memory, the application generally works with the data as strongly typed objects (e.g., an object representing a contact). In contrast, when the data to be accessed comes from a database, an Application Programming Interface (API) for interacting with the data is dramatically different. In the latter case, data is generally exposed as a structured tuple (e.g., a data record representing the results of a query against invoices). A tuple is usually defined as a finite function that maps field names to a certain value. Its purpose is typically to indicate that a certain entity or object consists of certain components and/or has certain properties, but here these components are identified by a unique field name and not by a position, which often leads to a more user-friendly notation.
Traditionally, there has been a fairly large division between how applications work with data in memory and interact with data from a database. Data from a database typically comes in terms of tuples, e.g., records of data, in a streaming fashion that the applications must convert to memory representations that are used within the application. Accordingly, most applications of any size have what is called a data access layer or data abstractions layer, which is essentially an abstraction that provides common services and common data modeling abstractions over the data that comes out of the database. The code within those abstraction layers is generally common and typically performs many of the same functions. Thus, in the object-oriented world, it has become increasingly popular to provide a pre-canned abstraction layer which will in a generic fashion take those tuples of flat relational data and turn them into objects within the object language.
Because APIs can differ depending upon where data resides, a number of “Object-Relational Mapping” products have been introduced which attempt to bridge this gap by mapping objects to relational stores. Due to the nature of this mapping, additional services may be supported over the data, such as a looser coupling between the database schema and the object schema, state management services, and update processing. However, because these services build upon an object API (e.g., at an object layer) as opposed to a relational API, they are tightly bound to the object view of the data. Accordingly, these services are only available when using a separate object API, which typically incurs overhead, for example, in object creation and identity management. Additionally, this object API generally requires that the types being queried have been previously installed on the client machine.
Further, developers accessing a database may be required to write to storage-specific components (e.g., “providers” or sometimes referred to as “data providers”, “drivers” or other terms) or rely upon a factory model and generic interfaces or base classes, or a common abstraction layer, in order to work across multiple providers. Even with generic interfaces, base classes, or a common abstraction layer, a developer must deal with command syntax differences across different stores, yet storage-specific providers generally expose native storage-specific query syntax. Therefore, it is often difficult to produce storage-independent code. Moreover, a database application might need a client-side nested relational transformation, yet most relational stores today expose only a non-nested (e.g., “flat”) relational model.
In addition, developers may want results returned as typed objects that can contain business logic. As well, when modeling results as business objects, developers often want changes to those business objects to be tracked and later persisted. Furthermore, developers may desire support for current and future operating systems, such as operating systems that bridge disparate types of data representations with metadata.